Skip to content

Implement onBindableContainerDidLoad and onBindableContainerDidUnload on BindableContainer#117

Merged
Maks-Jago merged 22 commits into
1.5.2from
feature/implement-onbindablecontainerdidload-and-onbindablecontainerdidunload-on-bindablecontainer-guid_869dh0kpx
Jul 2, 2026
Merged

Implement onBindableContainerDidLoad and onBindableContainerDidUnload on BindableContainer#117
Maks-Jago merged 22 commits into
1.5.2from
feature/implement-onbindablecontainerdidload-and-onbindablecontainerdidunload-on-bindablecontainer-guid_869dh0kpx

Conversation

@killlilwinters

@killlilwinters killlilwinters commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Description

This merge request adds lifecycle hooks for bindable container state creation and teardown, so container-specific setup/cleanup can run exactly once per bound state instance rather than on every view appearance.

The problem addressed here is that BindableContainer previously exposed only generic load/unload callbacks tied to the view lifecycle. That makes it hard to distinguish between:

  • a new bound reducer/state being created for a container ID, and
  • another view instance reusing an already existing bound state.

To solve this, the MR introduces reducer introspection and reference-count checks to detect whether a reducer for a given bindable container ID already exists and whether the current instance is the last one before unload. This allows calling dedicated hooks only when the bound state is first loaded or finally released.

An alternative would have been to move this logic fully into reducer/store internals and emit explicit state lifecycle events, but this implementation keeps the feature localized to bindable containers and existing reducer storage.

Changes Made

  • Added new bindable container lifecycle hooks:

    • onBindableContainerStateDidLoad(store:)
    • onBindableContainerStateDidUnload(store:)
  • Provided default no-op implementations so existing containers remain source-compatible.

  • Wired these new hooks through BindableContainer.connected(...) into ConnectedContainer.

  • Introduced AnyBindableReducer to expose runtime metadata and reducer-instance checks:

    protocol AnyBindableReducer: Sendable {
        var boundContainerType: any Any.Type { get }
        func hasReducer(for id: any Hashable) -> Bool
        func isLastInstance(for id: any Hashable) -> Bool
    }
  • Made BindableReducer conform to AnyBindableReducer by exposing:

    • the bound container type,
    • whether a reducer exists for a given container ID,
    • whether that reducer is the last referenced instance.
  • Extended RCDictionary with uniqueness detection:

    • added isUniquelyReferenced(key:)
    • exposed ReducerBox.referenceCount as private(set) so it can be inspected externally without allowing mutation.
  • Updated ConnectedContainer to invoke the new state lifecycle hooks conditionally:

    • call onBindableContainerStateDidLoad only when no reducer exists yet for the container ID,
    • call onBindableContainerStateDidUnload only when the current reducer instance is the last active one.
  • Added runtime-based reducer lookup in ConnectedContainer using Runtime.typeInfo to find the matching BindableReducer inside app state by container type.

ClickUp task

https://app.clickup.com/t/869dh0kpx

@killlilwinters killlilwinters added the enhancement New feature or request label Jun 1, 2026
@killlilwinters killlilwinters marked this pull request as draft June 1, 2026 18:31
@killlilwinters

killlilwinters commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator Author

Додав кешування:

AppState Size (N) Raw Baseline (ms) Optimized Caching (ms) Speedup Factor Average Lookup Speed
100 properties 272.37 ms 1.47 ms 185x ~1.47 microseconds
500 properties 2260.18 ms 5.50 ms 411x ~5.50 microseconds
1000 properties 8223.49 ms 15.34 ms 536x ~15.34 microseconds

Залишилось додати delayed onBindableCotnainerStateDidLoad callback, щоб ми не отримували колбек коли редюсер для нас ще nil і ми не можемо його читати + вигадати назви новим lifecycle методам.

Edit: + тести, звичайно.

@killlilwinters killlilwinters marked this pull request as ready for review June 10, 2026 15:39
Comment thread UDF/View/Container/ContainerLifecycle.swift
Comment thread UDF/View/Container/ContainerLifecycle.swift
Comment thread Tests/SwiftUI-UDF-Tests/BindableReducers/BindableContainerLifecycleTests.swift Outdated
Comment thread UDF/View/Container/ConnectedContainer.swift Outdated
Comment thread UDF/Store/Reducer/BindableReducer.swift Outdated
Comment thread UDF/View/Container/ContainerLifecycle.swift
}

// MARK: - Environment-Aware Container
public extension BindableContainer {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Public ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

Comment thread Tests/SwiftUI-UDF-Tests/BindableReducers/BindableContainerLifecycleTests.swift Outdated
@Sashe0

Sashe0 commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

conflicts

#Conflicts:
#	Tests/SwiftUI-UDF-Tests/Dialog/DialogQueueTests.swift
#	Tests/SwiftUI-UDF-Tests/Dialog/ToastDismissCallbackTests.swift
@Maks-Jago Maks-Jago merged commit d851dad into 1.5.2 Jul 2, 2026
1 check passed
@Maks-Jago Maks-Jago deleted the feature/implement-onbindablecontainerdidload-and-onbindablecontainerdidunload-on-bindablecontainer-guid_869dh0kpx branch July 2, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants